﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using WindowsInput;
using WindowsInput.Native;

namespace PCRemotePCver
{
    public enum ShutdownState { SHUTDOWN, RESTART, SLEEP, HIBERNATE, LOGOFF, LOCK }
   
    public static class CommandExecution
    {
        [DllImport("wtsapi32.dll", SetLastError = true)]
        static extern bool WTSDisconnectSession(IntPtr hServer, int sessionId, bool bWait);
        const int WTS_CURRENT_SESSION = -1;
        static readonly IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
        private const int WmSyscommand = 0x0112;
        private const int ScMonitorpower = 0xF170;
        private const int HwndBroadcast = 0xFFFF;
        private const int ShutOffDisplay = 2;

        public static InputSimulator inputSimulator = new InputSimulator();
        public static void ExcuseCommand(string content)
        {
            string backup = string.Copy(content);
            content = content.ToUpper();
            Console.WriteLine("Remote send command : " + content);

            if (content.IndexOf("SLEEP", System.StringComparison.Ordinal) > -1)
            {
                CommandExecution.Shutdown(ShutdownState.SLEEP);
            }
            if (content.IndexOf("SHUTDOWN", System.StringComparison.Ordinal) > -1)
            {
                CommandExecution.Shutdown(ShutdownState.SHUTDOWN);
            }
            if (content.IndexOf("RESTART", System.StringComparison.Ordinal) > -1)
            {
                CommandExecution.Shutdown(ShutdownState.RESTART);
            }
            if (content.IndexOf("HIBERNATE", System.StringComparison.Ordinal) > -1)
            {
                CommandExecution.Shutdown(ShutdownState.HIBERNATE);
            }
            if (content.IndexOf("LOGOUT", System.StringComparison.Ordinal) > -1)
            {
                CommandExecution.Shutdown(ShutdownState.LOGOFF);
            }
            if (content.IndexOf("LOCKSESSION", System.StringComparison.Ordinal) > -1)
            {
                CommandExecution.Shutdown(ShutdownState.LOCK);
            }
            if (content.IndexOf("TAKESNAP", System.StringComparison.Ordinal) > -1)
            {
                AsynchronousSocketListener.SendImage(imageToByteArray(GetScreenShot()));
            }
            //Mouse Remoute
            if (content.IndexOf("MOUSECLICK", StringComparison.Ordinal) > -1)
            {
                inputSimulator.Mouse.LeftButtonClick();
            }
            if (content.IndexOf("DOUBLECLICK", StringComparison.Ordinal) > -1)
            {
                inputSimulator.Mouse.LeftButtonDoubleClick();
            }
            if (content.IndexOf("RIGHTCLICK", StringComparison.Ordinal) > -1)
            {
                inputSimulator.Mouse.RightButtonClick();
            }
            if (content.IndexOf("MOUSEMOVE", StringComparison.Ordinal) > -1)
            {
                //get new position
                Regex rg = new Regex(@"\({X:(?<posX>\d+).Y:(?<posY>\d+)}\)");
                var ms = rg.Matches(content);
                foreach (Match m in ms)
                {
                    int posX = int.Parse(m.Groups["posX"].Value);
                    int posY = int.Parse(m.Groups["posY"].Value);
                    inputSimulator.Mouse.MoveMouseTo(posX * 65530.0 / 800.0, posY * 65535.0 / 480.0);
                }
            }
            //SendKey
            if (content.IndexOf("SENDKEY", System.StringComparison.Ordinal) > -1)
            {
                KeyDown(content);
            }
            if (content.ToUpper().IndexOf("COMBOKEY", System.StringComparison.Ordinal) > -1)
            {
                ComboKeys(content);
            }
            if (content.IndexOf("KEYTYPE", System.StringComparison.Ordinal) > -1)
            {
                string sub = backup.Substring(content.IndexOf(':') + 1, content.Length - 13);
                inputSimulator.Keyboard.TextEntry(sub);
            }
            if (content.IndexOf("OPEN", StringComparison.Ordinal) > -1)
            {
                OpenProgram(content);
            }
            if (content.IndexOf("VOLUMNE", StringComparison.Ordinal) > -1)
            {
                VolumeAdjuster(content);
            }
        }
        private static VirtualKeyCode GetKeyCode(string keycode)
        {
            switch (keycode)
            {
                case "F1":
                    return VirtualKeyCode.F1;
                case "F2":
                    return VirtualKeyCode.F2;
                case "F3":
                    return VirtualKeyCode.F3;
                case "F4":
                    return VirtualKeyCode.F4;
                case "F5":
                    return VirtualKeyCode.F5;
                case "F6":
                    return VirtualKeyCode.F6;
                case "F7":
                    return VirtualKeyCode.F7;
                case "F8":
                    return VirtualKeyCode.F8;
                case "F9":
                    return VirtualKeyCode.F9;
                case "F10":
                    return VirtualKeyCode.F10;
                case "F11":
                    return VirtualKeyCode.F11;
                case "F12":
                    return VirtualKeyCode.F12;
                case "CTRL":
                    return VirtualKeyCode.CONTROL;
                case "ALT":
                    return VirtualKeyCode.MENU;
                case "SHIFT":
                    return VirtualKeyCode.SHIFT;
                case "ESC":
                    return VirtualKeyCode.ESCAPE;

                default:
                    return VirtualKeyCode.FINAL;
            }
        }
        public static void ComboKeys(string keyStr)
        {
            string keys = keyStr.Substring(9, keyStr.Length - 14);
            string[] keyArr = keys.Split('_');
            if (keyArr.Length == 1)
            {
                inputSimulator.Keyboard.KeyDown(GetKeyCode(keyArr[0]));
            }
            else
            {
                List<VirtualKeyCode> controls = new List<VirtualKeyCode>();
                for (int i = 0; i < keyArr.Length - 1; i++)
                {
                    controls.Add(GetKeyCode(keyArr[i]));
                }
                inputSimulator.Keyboard.ModifiedKeyStroke(controls, GetKeyCode(keyArr[keyArr.Length - 1]));
            }
        }
        public static void KeyDown(string content)
        {
            if (content.ToUpper().IndexOf("SENDKEY_F5", System.StringComparison.Ordinal) > -1)
            {
                inputSimulator.Keyboard.KeyDown(VirtualKeyCode.F5);
            }
            if (content.ToUpper().IndexOf("SENDKEY_ESC", System.StringComparison.Ordinal) > -1)
            {
                inputSimulator.Keyboard.KeyDown(VirtualKeyCode.ESCAPE);
            }
            if (content.ToUpper().IndexOf("SENDKEY_ENTER", System.StringComparison.Ordinal) > -1)
            {
                inputSimulator.Keyboard.KeyDown(VirtualKeyCode.RETURN);
            }
            if (content.ToUpper().IndexOf("SENDKEY_RIGHT", System.StringComparison.Ordinal) > -1)
            {
                inputSimulator.Keyboard.KeyDown(VirtualKeyCode.RIGHT);
            }
            if (content.ToUpper().IndexOf("SENDKEY_LEFT", System.StringComparison.Ordinal) > -1)
            {
                inputSimulator.Keyboard.KeyDown(VirtualKeyCode.LEFT);
            }
            if (content.ToUpper().IndexOf("SENDKEY_UP", System.StringComparison.Ordinal) > -1)
            {
                inputSimulator.Keyboard.KeyDown(VirtualKeyCode.UP);
            }
            if (content.ToUpper().IndexOf("SENDKEY_DOWN", System.StringComparison.Ordinal) > -1)
            {
                inputSimulator.Keyboard.KeyDown(VirtualKeyCode.DOWN);
            }
            if (content.ToUpper().IndexOf("SENDKEY_NEXTTRACK", System.StringComparison.Ordinal) > -1)
            {
                inputSimulator.Keyboard.KeyDown(VirtualKeyCode.MEDIA_NEXT_TRACK);
            }
            if (content.ToUpper().IndexOf("SENDKEY_PREVIOUSTRACK", System.StringComparison.Ordinal) > -1)
            {
                inputSimulator.Keyboard.KeyDown(VirtualKeyCode.MEDIA_PREV_TRACK);
            }
            if (content.ToUpper().IndexOf("SENDKEY_PLAY", System.StringComparison.Ordinal) > -1)
            {
                inputSimulator.Keyboard.KeyDown(VirtualKeyCode.MEDIA_PLAY_PAUSE);
            }
            if (content.ToUpper().IndexOf("SENDKEY_FULLSCREEN", System.StringComparison.Ordinal) > -1)
            {
                inputSimulator.Keyboard.KeyDown(VirtualKeyCode.RETURN);
            }
            if (content.ToUpper().IndexOf("SENDKEY_STOP", System.StringComparison.Ordinal) > -1)
            {
                inputSimulator.Keyboard.KeyDown(VirtualKeyCode.MEDIA_STOP);
            }
            if (content.ToUpper().IndexOf("SENDKEY_CTRL", System.StringComparison.Ordinal) > -1)
            {
                inputSimulator.Keyboard.KeyDown(VirtualKeyCode.CONTROL);
            }
            if (content.ToUpper().IndexOf("SENDKEY_ALT", System.StringComparison.Ordinal) > -1)
            {
                inputSimulator.Keyboard.KeyDown(VirtualKeyCode.MENU);
            }
            if (content.ToUpper().IndexOf("SENDKEY_SHIFT", System.StringComparison.Ordinal) > -1)
            {
                inputSimulator.Keyboard.KeyDown(VirtualKeyCode.SHIFT);
            }
            if (content.ToUpper().IndexOf("SENDKEY_TAB", System.StringComparison.Ordinal) > -1)
            {
                inputSimulator.Keyboard.KeyDown(VirtualKeyCode.TAB);
            }
            if (content.ToUpper().IndexOf("SENDKEY_BACK", System.StringComparison.Ordinal) > -1)
            {
                inputSimulator.Keyboard.KeyDown(VirtualKeyCode.BACK);
            }
            if (content.ToUpper().IndexOf("SENDKEY_DELETE", System.StringComparison.Ordinal) > -1)
            {
                inputSimulator.Keyboard.KeyDown(VirtualKeyCode.DELETE);
            }

        }
        //convet Image to byte[]
        public static byte[] imageToByteArray(Bitmap imageIn)
        {
            MemoryStream ms = new MemoryStream();
            imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
            return ms.GetBuffer();
        }
        private static Bitmap ResizeBitmap(Bitmap sourceBMP, int width, int height)
        {
            Bitmap result = new Bitmap(width, height);
            using (Graphics g = Graphics.FromImage(result))
                g.DrawImage(sourceBMP, 0, 0, width, height);
            return result;
        }
        private static Bitmap GetScreenShot()
        {
            Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);

            using (Graphics graphics = Graphics.FromImage(bitmap))
            {
                graphics.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
            }
            bitmap = ResizeBitmap(bitmap, 800, 480);
            return bitmap;
        }
        public static void OpenProgram(string program)
        {
            string cmd = program.Substring(program.IndexOf('_') + 1, program.Length - 10);
            switch (cmd)
            {
                case "POWERPOINT":
                    ProcessStartInfo startPP = new ProcessStartInfo();
                    startPP.FileName = "POWERPNT.EXE";
                    Process.Start(startPP);
                    break;
                case "EXPLORER":
                    Process.Start("C:\\");
                    break;
                case "WORD":
                    ProcessStartInfo startW = new ProcessStartInfo();
                    startW.FileName = "WINWORD.EXE";
                    Process.Start(startW);
                    break;
                case "BROWSER":
                    Process.Start("http://google.com");
                    break;
                case "NOTEPAD":
                    Process.Start("notepad.exe");
                    break;
            }
        }
        public static void VolumeAdjuster(string volumnStr)
        {
            string cmd = volumnStr.Substring(8, volumnStr.Length - 13);
            if (cmd.Equals("UP"))
            {
                inputSimulator.Keyboard.KeyDown(VirtualKeyCode.VOLUME_UP);
            }
            else if (cmd.Equals("DOWN"))
            {
                inputSimulator.Keyboard.KeyDown(VirtualKeyCode.VOLUME_DOWN);
            }
            else
            {
                inputSimulator.Keyboard.KeyDown(VirtualKeyCode.VOLUME_MUTE);
            }
        }
        public static void Shutdown(ShutdownState state)
        {
            
            switch (state)
            {
                case ShutdownState.SHUTDOWN:
                    System.Diagnostics.Process.Start("Shutdown", "-s -t 0");
                    break;
                case ShutdownState.RESTART:
                    System.Diagnostics.Process.Start("Shutdown", "-r -t 0");
                    break;
                case ShutdownState.SLEEP:
                    Application.SetSuspendState(PowerState.Suspend, true, true);
                    break;
                case ShutdownState.HIBERNATE:
                    Application.SetSuspendState(PowerState.Hibernate, true, true);
                    break;
                case ShutdownState.LOGOFF:
                    WTSDisconnectSession(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, false);
                    break;
                case ShutdownState.LOCK:
                    inputSimulator.Keyboard.KeyDown(VirtualKeyCode.SLEEP);
                    break;
                default:
                    throw new ArgumentOutOfRangeException("state");
            }
        }

    }
}
